package diva.pap.model;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import java.text.SimpleDateFormat;
import java.util.Date;

import static diva.android_library.lang.AndroidLang.asString;
import static diva.android_library.lang.AndroidLang.sleep;
import static diva.lib.lang.Lang.empty;
import static diva.lib.lang.Lang.error;
import static diva.lib.lang.Lang.info;
import static diva.lib.lang.Lang.is;
import static diva.lib.lang.Lang.json;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import diva.android_library.rpc.Request;
import diva.android_library.rpc.Response;
import diva.lib.json.JSONObject;
import diva.lib.lang.Lang;
import diva.lib.lang.Run;
import diva.lib.net.UrlBuilder;
import diva.pap.LoginRequest;
import diva.pap.R;

public class RequestBase<SELF_TYPE extends Request<SELF_TYPE>> implements Request<SELF_TYPE> {

  private static final String SERVER_SCRIPT_PATH = "/scripts/mobile.php";
  private static final String EXCEPTION = "exception";
  protected JSONObject data;
  protected final Application application = Application.getInstance();
  private final String action;
  private Context context;
  private ProgressDialog dialog;
  protected Response<SELF_TYPE> response;
  private int request_failed_message_id = R.string.request_failed;
  private final SimpleDateFormat timestampFormat = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");

  public RequestBase(Context context, String action, Response<SELF_TYPE> response) {
    setContext(context);
    this.action = action;
    setResponse(response);
  }

  public String getAction() {
    return action;
  }

  public UrlBuilder getUrl() {
    UrlBuilder url =
        new UrlBuilder(application.getSettings().getServerUrl() + SERVER_SCRIPT_PATH).add("action",
            action).add("session", application.getSessionId());
    addTimeStamp(url);
    return url;
  }

  public boolean isDone() {
    return is(data);
  }

  public boolean isSuccess() {
    return data.getBoolean("success");
  }

  public void run() {
    if (empty(application.getSessionId()))
      new LoginRequest(new Response<LoginRequest>() {
        public void onReuestDone(LoginRequest login) {
          process();
        }

        public void onReuestFailed() {
          sleep(3000);
          application.getRpc().postAtFrontOfQueue(RequestBase.this);
        }
      }).send();
    else process();
  }

  public void send() {
    if (is(context)) {
      dialog =
          ProgressDialog.show(context, "", context.getResources().getString(
              R.string.request_loading), true);
      application.getRpc().send(this);
    } else application.getRpc().send(this);
  }

  public void setContext(Context context) {
    this.context = context;
  }

  public void setRequestFailedMessage(int loginMsgRequestfailed) {
    request_failed_message_id = loginMsgRequestfailed;
  }

  public void setResponse(Response<SELF_TYPE> response) {
    this.response = response;
  }

  protected void addTimeStamp(UrlBuilder url) {
    CharSequence timestamp = timestampFormat.format(new Date());
    url.add("ts", timestamp);
  }

  protected UrlBuilder createLoginUrl(String url, String action, String username, String password) {
    UrlBuilder builder = new UrlBuilder(url + SERVER_SCRIPT_PATH);
    builder.add("action", action).add("username", username).add("password", password);
    addTimeStamp(builder);
    return builder;
  }

  protected void doLater(Runnable runnable) {
    Lang.doLater(runnable);
  }

  protected CharSequence getNumberString(String key) {
    return data.getNumber(key).intValue() + "";
  }

  protected CharSequence getString(String key) {
    return data.getString(key) + "";
  }

  @SuppressWarnings("unchecked")
  protected void onRequestSuccess(final Response<SELF_TYPE> response) {
    if (is(dialog)) dialog.dismiss();
    if (is(response)) response.onReuestDone((SELF_TYPE) this);
  }

  protected void process() {
    try {
      final JSONObject json = loadJsonObject(getUrl().asString());
      doLater(new Run() {
        public void run() {
          if (json.hasString(EXCEPTION)) {
            String excetion = json.getString(EXCEPTION);
            if (excetion.equals("session_expired")) {
              application.setSession(null);
              application.getRpc().postAtFrontOfQueue(RequestBase.this);
            } else {
              error(excetion);
              onResponseException(response);
            }
          } else {
            data = json;
            onRequestSuccess(response);
          }
        }
      });
    } catch (final Exception e) {
      doLater(new Run() {
        public void run() {
          error(e);
          onResponseException(response);
        }
      });
    }
  }

  private JSONObject loadJsonObject(String url) throws Exception {
    HttpGet get = new HttpGet(url);
    info(get.getURI());
    HttpResponse response = new DefaultHttpClient().execute(get);
    String jsonString = asString(response.getEntity().getContent());
    info("Retrived", jsonString);
    return json(jsonString).asObject();
  }

  private void onResponseException(final Response<SELF_TYPE> response) {
    if (is(dialog)) dialog.dismiss();
    if (is(context)) showFailedDialog();
    if (is(response)) response.onReuestFailed();
  }

  private void showFailedDialog() {
    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    builder.setMessage(context.getResources().getString(request_failed_message_id));
    builder.setCancelable(true);
    builder.create().show();
  }
}
